/*
 * Created by: vadikv
 * Created: Wednesday, March 05, 2008
 */

using System;
using System.Collections.Generic;
using OneDayModel.Interfaces;
using OneDayModel.Model;
using OneDayModel.Model.Repository;

namespace OneDayModel.PresentationLogic
{
    public class NewUserProfileUILogic
    {
        private readonly INewUserProfileUI newUserProfileUI;
        private readonly INewUserProfileModel newUserProfileModel;
        private string[] selectedRoles;
        private IRoleAttribute[] roleAttributes;

        public NewUserProfileUILogic(INewUserProfileUI newUserProfileUI, INewUserProfileModel newUserProfileModel)
        {
            this.newUserProfileUI = newUserProfileUI;
            this.newUserProfileModel = newUserProfileModel;
            SetInitialView();
            RegisterToEvents();
        }

        private void RegisterToEvents()
        {
            newUserProfileUI.onRolesSelection += newUserProfileUI_onRolesSelection;
            newUserProfileUI.onSaveProfile += newUserProfileUI_onSaveProfile;
            newUserProfileUI.onReturnToQuestioner += newUserProfileUI_onReturnToQuestioner;
        }

        void newUserProfileUI_onRolesSelection(object sender, RolesSelectionArgs e)
        {
            selectedRoles = e.SelectedRoles;
            roleAttributes = GetRoleAttributes();
            newUserProfileUI.ShowAttributes(BuildAttributesRecords(roleAttributes));
        }

        private IEnumerable<IAttributeRecord> BuildAttributesRecords(IRoleAttribute[] roleAttributes)
        {
            foreach (RoleAttribute attribute in roleAttributes)
            {
                yield return new AttributeRecord(attribute);
            }
        }

        private IRoleAttribute[] GetRoleAttributes()
        {
            IAttributesBuilder attributesBuilder = newUserProfileModel.NewAttributesBuilder();
            foreach (string selectedRole in selectedRoles)
            {
                attributesBuilder.AppendRole(selectedRole);
            }


            return attributesBuilder.Attributes;
        }

        void newUserProfileUI_onReturnToQuestioner(object sender, SaveProfileArgs e)
        {
            for (int i = 0; i < e.Attributes.Length; i++ )
            {
                if (e.Attributes[i].RoleAttribute.Name == "Password")
                {
                    e.Attributes[i].Value = string.Empty;
                    break;
                }
            }

            newUserProfileUI.ShowAttributes(e.Attributes);
        }

        void newUserProfileUI_onSaveProfile(object sender, SaveProfileArgs e)
        {
            string[] missedAttributes = CheckAttributesCompleteness(e.Attributes);
            if (missedAttributes.Length > 0)
            {
                newUserProfileUI.ShowMissingAttributesInfo(missedAttributes);
                newUserProfileUI.ShowBackToQuestioner();

                throw new MissingRequiredValuesException(missedAttributes);
            }

            string alias = GetAlias(e.Attributes);
            if (!newUserProfileModel.IsAliasUnique(alias))
                throw new AliasNotUniqueException(alias);

            string email = GetEmail(e.Attributes);
            AccountStatus accountStatus = newUserProfileModel.GetAccountStatus(email);
            if (accountStatus != AccountStatus.notExist)
            {
                newUserProfileUI.ShowNewEMailOption();

                if (accountStatus == AccountStatus.existAndActive)
                    newUserProfileUI.ShowRetrieveCredantials(email);

                throw new AccountAlreadyExistException(email, accountStatus);
            }

            newUserProfileModel.CreateAndSaveNewUser(selectedRoles, e.Attributes);
        }

        private string[] CheckAttributesCompleteness(IAttributeRecord[] attributes)
        {
            List<string> result = new List<string>();
            foreach (AttributeRecord attribute in attributes)
            {
                if (attribute.RoleAttribute.Required && string.IsNullOrEmpty(attribute.Value))
                    result.Add( attribute.RoleAttribute.DisplayName);
            }
            return result.ToArray();
        }

        private string GetEmail(IAttributeRecord[] attributes)
        {
            foreach (AttributeRecord attribute in attributes)
            {
                if (attribute.RoleAttribute.Name == "eMail")
                    return attribute.Value;
            }

            return null;
        }

        private string GetAlias(IAttributeRecord[] attributes)
        {
            foreach (AttributeRecord attribute in attributes)
            {
                if (attribute.RoleAttribute.Name == "Alias")
                    return attribute.Value;
            }
            return null;
        }

        private void SetInitialView()
        {
            newUserProfileUI.SetAvailableRoles(newUserProfileModel.Roles);
        }
    }

    public class MissingRequiredValuesException : ApplicationException
    {
        private readonly string[] missedAttributes;

        public MissingRequiredValuesException(string[] missedAttributes) : base ("Required Attributes has no value")
        {
            this.missedAttributes = missedAttributes;
        }

        public string[] MissedAttributes
        {
            get { return missedAttributes; }
        }
    }

    public class AccountAlreadyExistException : ApplicationException
    {
        private readonly AccountStatus accountStatus;

        public AccountAlreadyExistException(string email, AccountStatus accountStatus)
            : base("User with e-mail \"" + email + "\" already exist")
        {
            this.accountStatus = accountStatus;
        }

        public AccountStatus AccountStatus
        {
            get { return accountStatus; }
        }
    }

    public class AliasNotUniqueException : ApplicationException
    {
        public AliasNotUniqueException(string alias) : 
            base("Alias \"" + alias + "\"" + " is not unique"){}
    }
}